#include "cfgparser.h"

#include <fstream>
#include <filesystem>
#include <system_error>
#include <vector>
#include <utility>

namespace cfgparser
{

    CFGParser::CFGParser()
        : CFGParser(
              ::cfgparser::get_executable_directory() + "/" + ::cfgparser::get_app_name() + ".cfg",
              CFGParserOptions{})
    {
    }

    CFGParser::CFGParser(const std::string &config_file_path)
        : CFGParser(config_file_path, CFGParserOptions{})
    {
    }

    CFGParser::CFGParser(const std::string &config_file_path, CFGParserOptions options)
        : __config_file_path(config_file_path), __options(std::move(options))
    {
        if (__options.create_if_not_exists && !__config_file_path.empty())
        {
            (void)ensure_config_file_exists();
        }

        if (__options.auto_load_on_construction && !__config_file_path.empty())
        {
            (void)load();
        }
        // 如果配置中启用了基于变更的自动保存，初始化去抖延迟
        if (__options.auto_save_on_change)
        {
            __autosave_delay = std::chrono::milliseconds(__options.auto_save_debounce_ms);
        }
    }

    CFGParser::~CFGParser()
    {
        // 停止并回收后台 autosave 线程（若已启动）
        __autosave_stop.store(true);
        __autosave_cv.notify_all();
        if (__autosave_thread.joinable())
            __autosave_thread.join();

        // 如果启用了析构时自动保存且有未持久化的数据，则在析构时保存一次
        if (__options.auto_save_on_destruction && is_dirty() && !__config_file_path.empty())
        {
            (void)save();
        }
    }

    const std::string &CFGParser::get_config_file_path() const
    {
        return __config_file_path;
    }

    bool CFGParser::load()
    {
        if (__config_file_path.empty())
        {
            return false;
        }

        if (__options.create_if_not_exists)
        {
            std::filesystem::path input_path(__config_file_path);
            if (!std::filesystem::exists(input_path))
            {
                if (!ensure_config_file_exists())
                {
                    return false;
                }
            }
        }

        std::lock_guard<std::mutex> io_lock(__io_mutex);

        if (__options.backup_on_load)
        {
            if (!backup_config_file())
            {
                return false;
            }
        }

        std::ifstream input(__config_file_path, std::ios::binary | std::ios::ate);
        if (!input.is_open())
        {
            return false;
        }

        std::streamsize file_size = input.tellg();
        if (file_size <= 0)
        {
            return false;
        }

        input.seekg(0, std::ios::beg);

        std::vector<uint8_t> buffer(static_cast<size_t>(file_size));
        if (!input.read(reinterpret_cast<char *>(buffer.data()), file_size))
        {
            return false;
        }

        return deserialize(buffer.data(), buffer.size());
    }

    bool CFGParser::reload(const std::string &config_file_path)
    {
        if (!config_file_path.empty())
        {
            std::lock_guard<std::mutex> lock(__io_mutex);
            __config_file_path = config_file_path;
        }
        return load();
    }

    bool CFGParser::save_as(const std::string &config_file_path)
    {
        if (config_file_path.empty())
        {
            return false;
        }

        std::lock_guard<std::mutex> io_lock(__io_mutex);

        std::filesystem::path output_path(config_file_path);
        if (!output_path.parent_path().empty())
        {
            std::error_code ec;
            std::filesystem::create_directories(output_path.parent_path(), ec);
            if (ec)
            {
                return false;
            }
        }

        SerializedSnapshot snapshot = __snapshot();
        if (snapshot.buffer.empty())
        {
            return false;
        }

        std::ofstream output(config_file_path, std::ios::binary | std::ios::trunc);
        if (!output.is_open())
        {
            return false;
        }

        output.write(reinterpret_cast<const char *>(snapshot.buffer.data()),
                     static_cast<std::streamsize>(snapshot.buffer.size()));
        output.flush();

        bool success = output.good();
        if (success)
        {
            mark_clean_if_version_matches(snapshot.version);
        }

        return success;
    }

    bool CFGParser::save()
    {
        return save_as(__config_file_path);
    }

    CFGParser &CFGParser::set_options(const CFGParserOptions &options)
    {
        bool trigger_auto_load = false;
        bool trigger_create = false;
        {
            std::lock_guard<std::mutex> lock(__io_mutex);
            trigger_auto_load = options.auto_load_on_construction && !__options.auto_load_on_construction;
            trigger_create = options.create_if_not_exists && !__options.create_if_not_exists;
            __options = options;
        }

        if (trigger_create && !__config_file_path.empty())
        {
            (void)ensure_config_file_exists();
        }

        if (trigger_auto_load && !__config_file_path.empty())
        {
            (void)load();
        }

        return *this;
    }

    void CFGParser::__notify_autosave()
    {
        // 仅在配置中启用 "变更自动保存" 时才启动或通知后台线程
        if (!__options.auto_save_on_change)
            return;

        std::lock_guard<std::mutex> lk(__autosave_mtx);
        if (!__autosave_running.load())
        {
            // 启动后台线程
            __autosave_stop.store(false);
            __autosave_pending = true;
            __autosave_delay = std::chrono::milliseconds(__options.auto_save_debounce_ms);
            __autosave_thread = std::thread(&CFGParser::__autosave_thread_loop, this);
            __autosave_running.store(true);
            __autosave_cv.notify_one();
            return;
        }

        // 线程已运行：标记为待处理并通知，以重置去抖计时
        __autosave_pending = true;
        __autosave_cv.notify_one();
    }

    void CFGParser::__autosave_thread_loop()
    {
        std::unique_lock<std::mutex> lk(__autosave_mtx);
        while (!__autosave_stop.load())
        {
            // 等待直到有待处理的保存请求或收到停止信号
            if (!__autosave_pending)
            {
                __autosave_cv.wait(lk, [this]()
                                   { return __autosave_pending || __autosave_stop.load(); });
                if (__autosave_stop.load())
                    break;
            }

            // 去抖：等待去抖延迟，如果在等待期间收到新的通知则重置等待时间
            auto wake_time = std::chrono::steady_clock::now() + __autosave_delay;
            while (!__autosave_stop.load())
            {
                if (__autosave_cv.wait_until(lk, wake_time) == std::cv_status::timeout)
                    break; // timed out -> time to save
                // 再次通知：延长唤醒时间
                wake_time = std::chrono::steady_clock::now() + __autosave_delay;
            }

            if (__autosave_stop.load())
                break;

            // 如果数据为脏（有变更）则执行保存
            if (!__config_file_path.empty() && is_dirty())
            {
                // 在保存期间释放 autosave 锁以避免长期占用
                lk.unlock();
                try
                {
                    (void)save();
                }
                catch (...)
                {
                }
                lk.lock();
            }

            __autosave_pending = false;
        }

        // 线程退出前的清理
        __autosave_running.store(false);
    }

    CFGParserOptions CFGParser::get_options() const
    {
        std::lock_guard<std::mutex> lock(__io_mutex);
        return __options;
    }

    bool CFGParser::ensure_config_file_exists()
    {
        if (__config_file_path.empty())
        {
            return false;
        }

        std::filesystem::path output_path(__config_file_path);
        if (!output_path.parent_path().empty())
        {
            std::error_code ec;
            std::filesystem::create_directories(output_path.parent_path(), ec);
            if (ec)
            {
                return false;
            }
        }

        if (std::filesystem::exists(output_path))
        {
            return true;
        }

        return save();
    }

    bool CFGParser::backup_config_file()
    {
        if (__config_file_path.empty())
        {
            return false;
        }

        if (__options.backup_suffix.empty())
        {
            return true;
        }

        std::filesystem::path original_path(__config_file_path);
        if (!std::filesystem::exists(original_path))
        {
            return true;
        }

        std::filesystem::path backup_path = original_path;
        backup_path += __options.backup_suffix;

        std::error_code ec;
        std::filesystem::copy_file(original_path, backup_path,
                                   std::filesystem::copy_options::overwrite_existing,
                                   ec);
        return !ec;
    }

}